﻿#pragma once
#include <string>
#include <memory>
#include <atomic>
#include <csignal>
#include <mutex>

namespace app
{
    // Application 基类，CRTP 实现
    template <typename Derived>
    class Application
    {
    public:
        // 全局单例访问点
        static Derived& instance()
        {
            static Derived inst;
            return inst;
        }

        int main(int argc, char* argv[])
        {
            std::lock_guard<std::mutex> lk(mtx_);
            if (inited_) return exitCode_; // 防止重复进入
            inited_ = true;

            // // 3. 安装信号
            // installSignal();

            // 4. 派生类初始化
            if (!static_cast<Derived*>(this)->onInit())
            {
                return exitCode_ = 3;
            }

            // 5. 运行
            exitCode_ = static_cast<Derived*>(this)->onRun();

            // 6. 清理
            static_cast<Derived*>(this)->onCleanup();
            return exitCode_;
        }

        void quit(int code = 0)
        {
            exitCode_ = code;
            running_ = false;
        }

        bool isRunning() const
        {
            return running_;
        }

        // 三个钩子，派生类可选重写
         bool onInit() {return true;};
         int onRun() {return 0;};
         void onCleanup() {};

    protected:
        Application() = default;
        ~Application() = default;

    private:
        void installSignal()
        {
            auto handler = [](int) { instance().quit(1); };
            std::signal(SIGINT, handler);
            std::signal(SIGTERM, handler);
#ifdef _WIN32
            std::signal(SIGBREAK, handler);
#endif
        }

        static std::atomic<bool> running_;
        static std::atomic<int> exitCode_;
        static std::mutex mtx_;
        std::atomic<bool> inited_ {false};
    };

    template <typename Derived>
    std::atomic<bool> Application<Derived>::running_{true};

    template <typename Derived>
    std::atomic<int> Application<Derived>::exitCode_{0};

    template <typename Derived>
    std::mutex Application<Derived>::mtx_;
} // namespace app
